// Copyright 2021 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Author: Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
//         Basile Bougenot <bbougenot@student.ethz.ch>
//         Matteo Perotti <mperotti@iis.ee.ethz.ch>

#include "vector_macros.h"
#include "float_macros.h"

// Simple random test with similar values
void TEST_CASE1(void) {
  VSET(16, e16, m1);
  //               33.9375,  31.7344, -56.0000, -62.0625,  77.6875, -7.7383, -75.3750,  4.1953,  79.5625, -87.3750, -37.2188,  90.5000,  68.0625,  69.0625,  54.0312, -64.6875
  VLOAD_16(v2,     0x503e,  0x4fef,  0xd300,  0xd3c2,  0x54db,  0xc7bd,  0xd4b6,  0x4432,  0x54f9,  0xd576,  0xd0a7,  0x55a8,  0x5441,  0x5451,  0x52c1,  0xd40b);
  //              -92.3125, -75.9375,  26.1094, -79.6875,  3.9375,  37.2812,  50.7812, -3.9375, -55.9688, -31.5312,  76.0000,  69.1875, -8.2578, -52.5000, -98.4375,  40.3438
  VLOAD_16(v6,     0xd5c5,  0xd4bf,  0x4e87,  0xd4fb,  0x43e0,  0x50a9,  0x5259,  0xc3e0,  0xd2ff,  0xcfe2,  0x54c0,  0x5453,  0xc821,  0xd290,  0xd627,  0x510b);
  //               75.62483215,  29.19676971,  69.45310211, -70.36167145, -0.92180759, -77.84928131,  86.66299438, -43.34124756, -3.36894345,  7.33576536, -64.43717194, -80.48993683, -5.57641745,  89.34833527, -39.19780731, -55.64332581
  VLOAD_32(v4,     0x42973fea,  0x41e992fc,  0x428ae7fd,  0xc28cb92d,  0xbf6bfb95,  0xc29bb2d5,  0x42ad5374,  0xc22d5d70,  0xc0579cc5,  0x40eabe97,  0xc280dfd5,  0xc2a0fad9,  0xc0b27203,  0x42b2b259,  0xc21cca8e,  0xc25e92c4);
  asm volatile("vfwnmacc.vv v4, v2, v6");
  //               3057.23071289,  2380.63232422,  1392.67187500, -4875.24365234, -304.97271729,  366.34207153,  3740.97363281,  59.86029053,  4456.38281250, -2762.37866211,  2893.06225586, -6180.97900391,  567.62377930,  3536.43286133,  5357.89892578,  2665.37963867
  VCMP_U32(1, v4,  0x453f13b1,  0x4514ca1e,  0x44ae1580,  0xc59859f3,  0xc3987c82,  0x43b72bc9,  0x4569cf94,  0x426f70f0,  0x458b4310,  0xc52ca60f,  0x4534d0ff,  0xc5c127d5,  0x440de7ec,  0x455d06ed,  0x45a76f31,  0x45269613);

  VSET(16, e32, m1);
  //               24686.12304688,  45012.43359375,  5708.16113281, -32777.98828125,  74121.31250000, -74877.15625000, -60082.02734375,  46400.20312500, -45509.65234375, -63994.57031250, -8693.70019531,  57683.04296875,  70424.14843750,  90967.72656250,  16158.18359375, -90782.41406250
  VLOAD_32(v2,     0x46c0dc3f,  0x472fd46f,  0x45b2614a,  0xc70009fd,  0x4790c4a8,  0xc7923e94,  0xc76ab207,  0x47354034,  0xc731c5a7,  0xc779fa92,  0xc607d6cd,  0x4761530b,  0x47898c13,  0x47b1abdd,  0x467c78bc,  0xc7b14f35);
  //              -87108.13281250, -7857.04492188, -40309.92968750, -77418.73437500,  28954.62109375, -28385.13085938,  42368.34375000, -32644.74804688,  89327.02343750, -91567.60156250, -25929.78515625, -88250.83593750, -49992.60156250,  34217.12500000,  49765.98046875,  8088.22802734
  VLOAD_32(v6,     0xc7aa2211,  0xc5f5885c,  0xc71d75ee,  0xc797355e,  0x46e2353e,  0xc6ddc243,  0x47258058,  0xc6ff097f,  0x47ae7783,  0xc7b2d7cd,  0xc6ca9392,  0xc7ac5d6b,  0xc743489a,  0x4705a920,  0x474265fb,  0x45fcc1d3);
  //              -95159.7034957902651513, -25746.0480722606444033, -89272.3172746254567755, -57390.5516721799431252,  98139.9797031646012329, -66607.6782029465102823,  67788.7602550606534351, -90593.7788542728667380, -68056.0128839309472824, -37127.9738570771587547,  21060.8546093095501419, -76483.1707763712329324,  83261.7813338561973069, -99608.0446094776270911,  32602.1877863906847779,  52037.0826651407405734
  VLOAD_64(v4,     0xc0f73b7b4184cd41,  0xc0d92483139dacd4,  0xc0f5cb85138e8ec3,  0xc0ec05d1a74c6a5f,  0x40f7f5bfacdd39bc,  0xc0f042fad9eb5535,  0x40f08ccc2a0135e2,  0xc0f61e1c762fe5e5,  0xc0f09d8034c5c7e1,  0xc0e220ff29d6512c,  0x40d49136b1eb3ed8,  0xc0f2ac32bb800116,  0x40f453dc8057edfa,  0xc0f85180b6b86d78,  0x40dfd68c04b135a8,  0x40e968a2a5315d80);
  asm volatile("vfwnmacc.vv v4, v2, v6");
  //               2150457244.6964006423950195,  353690458.8370813727378845,  230184846.2258668541908264, -2537572977.5412845611572266, -2146252658.3886387348175049, -2125331270.8559157848358154,  2545508198.9366445541381836,  1514813534.1183013916015625,  4065309837.5555171966552734, -5859792188.5645341873168945, -225446839.1319110989570618,  5090653244.5816955566406250,  3520603131.4329605102539062, -3112554462.7102732658386230, -804160451.3248255252838135,  734216828.7275727987289429
  VCMP_U64(2, v4,  0x41e005abf39648ea,  0x41b514e35ad64af7,  0x41ab70af1c73a4d2,  0xc1e2e8094e315234,  0xc1dffb4ddc98df75,  0xc1dfab7ed1b6c753,  0x41e2f72becddf8fe,  0x41d6928e17879240,  0x41ee49f691b1c6cc,  0xc1f5d45553c90855,  0xc1aae0176e4389da,  0x41f2f6d343c94ea0,  0x41ea3b047f6ddad0,  0xc1e730b9fbd6ba8f,  0xc1c7f741e1a993e2,  0x41c5e1a13e5d211b);
};

// Simple random test with similar values (masked)
// The numbers are the same of TEST_CASE1
void TEST_CASE2(void) {
  VSET(16, e16, m1);
  //               33.9375,  31.7344, -56.0000, -62.0625,  77.6875, -7.7383, -75.3750,  4.1953,  79.5625, -87.3750, -37.2188,  90.5000,  68.0625,  69.0625,  54.0312, -64.6875
  VLOAD_16(v2,     0x503e,  0x4fef,  0xd300,  0xd3c2,  0x54db,  0xc7bd,  0xd4b6,  0x4432,  0x54f9,  0xd576,  0xd0a7,  0x55a8,  0x5441,  0x5451,  0x52c1,  0xd40b);
  //              -92.3125, -75.9375,  26.1094, -79.6875,  3.9375,  37.2812,  50.7812, -3.9375, -55.9688, -31.5312,  76.0000,  69.1875, -8.2578, -52.5000, -98.4375,  40.3438
  VLOAD_16(v6,     0xd5c5,  0xd4bf,  0x4e87,  0xd4fb,  0x43e0,  0x50a9,  0x5259,  0xc3e0,  0xd2ff,  0xcfe2,  0x54c0,  0x5453,  0xc821,  0xd290,  0xd627,  0x510b);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               75.62483215,  29.19676971,  69.45310211, -70.36167145, -0.92180759, -77.84928131,  86.66299438, -43.34124756, -3.36894345,  7.33576536, -64.43717194, -80.48993683, -5.57641745,  89.34833527, -39.19780731, -55.64332581
  VLOAD_32(v4,     0x42973fea,  0x41e992fc,  0x428ae7fd,  0xc28cb92d,  0xbf6bfb95,  0xc29bb2d5,  0x42ad5374,  0xc22d5d70,  0xc0579cc5,  0x40eabe97,  0xc280dfd5,  0xc2a0fad9,  0xc0b27203,  0x42b2b259,  0xc21cca8e,  0xc25e92c4);
  asm volatile("vfwnmacc.vv v4, v2, v6, v0.t");
  //               75.62483215,  2380.63232422,  69.45310211, -4875.24365234, -0.92180759,  366.34207153,  86.66299438,  59.86029053, -3.36894345, -2762.37866211, -64.43717194, -6180.97900391, -5.57641745,  3536.43286133, -39.19780731,  2665.37963867
  VCMP_U32(3, v4,  0x42973fea,  0x4514ca1e,  0x428ae7fd,  0xc59859f3,  0xbf6bfb95,  0x43b72bc9,  0x42ad5374,  0x426f70f0,  0xc0579cc5,  0xc52ca60f,  0xc280dfd5,  0xc5c127d5,  0xc0b27203,  0x455d06ed,  0xc21cca8e,  0x45269613);

  VSET(16, e32, m1);
  //               24686.12304688,  45012.43359375,  5708.16113281, -32777.98828125,  74121.31250000, -74877.15625000, -60082.02734375,  46400.20312500, -45509.65234375, -63994.57031250, -8693.70019531,  57683.04296875,  70424.14843750,  90967.72656250,  16158.18359375, -90782.41406250
  VLOAD_32(v2,     0x46c0dc3f,  0x472fd46f,  0x45b2614a,  0xc70009fd,  0x4790c4a8,  0xc7923e94,  0xc76ab207,  0x47354034,  0xc731c5a7,  0xc779fa92,  0xc607d6cd,  0x4761530b,  0x47898c13,  0x47b1abdd,  0x467c78bc,  0xc7b14f35);
  //              -87108.13281250, -7857.04492188, -40309.92968750, -77418.73437500,  28954.62109375, -28385.13085938,  42368.34375000, -32644.74804688,  89327.02343750, -91567.60156250, -25929.78515625, -88250.83593750, -49992.60156250,  34217.12500000,  49765.98046875,  8088.22802734
  VLOAD_32(v6,     0xc7aa2211,  0xc5f5885c,  0xc71d75ee,  0xc797355e,  0x46e2353e,  0xc6ddc243,  0x47258058,  0xc6ff097f,  0x47ae7783,  0xc7b2d7cd,  0xc6ca9392,  0xc7ac5d6b,  0xc743489a,  0x4705a920,  0x474265fb,  0x45fcc1d3);
  VLOAD_8(v0, 0xAA, 0xAA);
  //              -95159.7034957902651513, -25746.0480722606444033, -89272.3172746254567755, -57390.5516721799431252,  98139.9797031646012329, -66607.6782029465102823,  67788.7602550606534351, -90593.7788542728667380, -68056.0128839309472824, -37127.9738570771587547,  21060.8546093095501419, -76483.1707763712329324,  83261.7813338561973069, -99608.0446094776270911,  32602.1877863906847779,  52037.0826651407405734
  VLOAD_64(v4,     0xc0f73b7b4184cd41,  0xc0d92483139dacd4,  0xc0f5cb85138e8ec3,  0xc0ec05d1a74c6a5f,  0x40f7f5bfacdd39bc,  0xc0f042fad9eb5535,  0x40f08ccc2a0135e2,  0xc0f61e1c762fe5e5,  0xc0f09d8034c5c7e1,  0xc0e220ff29d6512c,  0x40d49136b1eb3ed8,  0xc0f2ac32bb800116,  0x40f453dc8057edfa,  0xc0f85180b6b86d78,  0x40dfd68c04b135a8,  0x40e968a2a5315d80);
  asm volatile("vfwnmacc.vv v4, v2, v6, v0.t");
  //              -95159.7034957902651513,  353690458.8370813727378845, -89272.3172746254567755, -2537572977.5412845611572266,  98139.9797031646012329, -2125331270.8559157848358154,  67788.7602550606534351,  1514813534.1183013916015625, -68056.0128839309472824, -5859792188.5645341873168945,  21060.8546093095501419,  5090653244.5816955566406250,  83261.7813338561973069, -3112554462.7102732658386230,  32602.1877863906847779,  734216828.7275727987289429
  VCMP_U64(4, v4,  0xc0f73b7b4184cd41,  0x41b514e35ad64af7,  0xc0f5cb85138e8ec3,  0xc1e2e8094e315234,  0x40f7f5bfacdd39bc,  0xc1dfab7ed1b6c753,  0x40f08ccc2a0135e2,  0x41d6928e17879240,  0xc0f09d8034c5c7e1,  0xc1f5d45553c90855,  0x40d49136b1eb3ed8,  0x41f2f6d343c94ea0,  0x40f453dc8057edfa,  0xc1e730b9fbd6ba8f,  0x40dfd68c04b135a8,  0x41c5e1a13e5d211b);
};

// Simple random test with similar values (vector-scalar)
void TEST_CASE3(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //               85.2500, -7.6602, -81.8125, -37.2500, -48.0000,  14.9531,  25.9844,  96.1875,  46.5000, -77.4375,  45.5312, -68.7500,  58.8438, -70.5625, -45.9375, -90.5000
  VLOAD_16(v2,     0x5554,  0xc7a9,  0xd51d,  0xd0a8,  0xd200,  0x4b7a,  0x4e7f,  0x5603,  0x51d0,  0xd4d7,  0x51b1,  0xd44c,  0x535b,  0xd469,  0xd1be,  0xd5a8);
  //                             -47.9375
  BOX_HALF_IN_DOUBLE(dscalar_16,  0xd1fe);
  //               6.19335365, -81.26284790, -77.74858093,  15.38204670,  27.37081337,  48.81098938, -82.18785095,  3.87765026, -34.03960037, -92.34690857,  46.98464203,  28.09385681,  58.44809723,  57.04935455, -44.62148285,  83.52678680
  VLOAD_32(v4,     0x40c62ff4,  0xc2a28694,  0xc29b7f46,  0x41761cdd,  0x41daf76d,  0x42433e74,  0xc2a4602e,  0x40782b6c,  0xc208288d,  0xc2b8b19e,  0x423bf046,  0x41e0c038,  0x4269cada,  0x4264328a,  0xc2327c66,  0x42a70db7);
  asm volatile("vfwnmacc.vf v4, %[A], v2" :: [A] "f" (dscalar_16));
  //               4080.47851562, -285.94589233, -3844.13818359, -1801.05395508, -2328.37084961,  668.00445557,  1327.81384277,  4607.11083984,  2263.13330078, -3619.81323242,  2135.66967773, -3323.79687500,  2762.37426758, -3439.63916016, -2157.50732422, -4421.87060547
  VCMP_U32(5, v4,  0x457f07a8,  0xc38ef913,  0xc5704236,  0xc4e121ba,  0xc51185ef,  0x44270049,  0x44a5fa0b,  0x458ff8e3,  0x450d7222,  0xc5623d03,  0x45057ab7,  0xc54fbcc0,  0x452ca5fd,  0xc556fa3a,  0xc506d81e,  0xc58a2ef7);

  VSET(16, e32, m1);
  double dscalar_32;
  //               415907.75000000,  16644.92773438, -320087.15625000, -560497.81250000,  51200.66406250,  175961.67187500, -62272.61328125, -40134.65234375,  67972.27343750,  832511.06250000, -279323.15625000, -48243.37500000,  685093.43750000,  272952.25000000,  518086.00000000, -349626.18750000
  VLOAD_32(v2,     0x48cb1478,  0x468209db,  0xc89c4ae5,  0xc908d71d,  0x474800aa,  0x482bd66b,  0xc773409d,  0xc71cc6a7,  0x4784c223,  0x494b3ff1,  0xc8886365,  0xc73c7360,  0x49274257,  0x48854708,  0x48fcf8c0,  0xc8aab746);
  //                              -648299.93750000
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0xc91e46bf);
  //              -3761.4446916116867214,  251037.4171459318604320, -832277.7590174797223881, -817938.7112226528115571, -640813.8540152770001441, -87111.6097838475834578, -748981.3983645441476256,  259451.7965630525723100, -469164.5467169298790395, -204901.8221613015048206,  97767.4262132318690419, -208046.9794710964197293, -303699.6372622016351670, -710697.5104083393234760, -907884.7086961114546284, -326406.2730544115183875
  VLOAD_64(v4,     0xc0ad62e3ae9e7200,  0x410ea4eb56509b38,  0xc129662b849df069,  0xc128f6256c256024,  0xc1238e5bb5417d8a,  0xc0f54479c1acb530,  0xc126db6acbf67002,  0x410fabde5f5c7320,  0xc11ca2b22fd69018,  0xc109032e93c94df0,  0x40f7de76d1c4f740,  0xc1096577d5f4f134,  0xc112894e8c8e766c,  0xc125b05305543dea,  0xc12bb4d96ada377b,  0xc113ec19179b935e);
  asm volatile("vfwnmacc.vf v4, %[A], v2" :: [A] "f" (dscalar_32));
  //               269632972092.2103271484375000,  10790654572.4701824188232422, -207511651113.6687316894531250, -363369878873.9254760742187500,  33194028125.5312614440917969,  114076027990.5677947998046875, -40370582316.7976837158203125, -26019552057.8339157104492188,  44066889785.8108749389648438,  539717074688.6307373046875000, -181085282506.6039428710937500, -31275968950.3095932006835938,  444146336412.5474243164062500,  176955637312.9947814941406250,  335876029304.3336791992187500, -226662309098.3402404785156250
  VCMP_U64(6, v4,  0x424f63b0529e1aec,  0x420419629363c2ef,  0xc24828544194d599,  0xc25526a215567b3b,  0x421eea12b1762003,  0x423a8f760c56915b,  0xc222cc8c6659986a,  0xc2183b8b6ce755ee,  0x4224852ec0739f2b,  0x425f6a693fc0285e,  0xc24514c310654d4e,  0xc21d20c5a6d93d06,  0x4259da4bd0a72309,  0x424499b05f207f55,  0x42538cf15ede155b,  0xc24a63102e752b8d);
};

// Simple random test with similar values (vector-scalar) (masked)
void TEST_CASE4(void) {
  VSET(16, e16, m1);
  double dscalar_16;
  //                85.2500, -7.6602, -81.8125, -37.2500, -48.0000,  14.9531,  25.9844,  96.1875,  46.5000, -77.4375,  45.5312, -68.7500,  58.8438, -70.5625, -45.9375, -90.5000
  VLOAD_16(v2,      0x5554,  0xc7a9,  0xd51d,  0xd0a8,  0xd200,  0x4b7a,  0x4e7f,  0x5603,  0x51d0,  0xd4d7,  0x51b1,  0xd44c,  0x535b,  0xd469,  0xd1be,  0xd5a8);
  //                             -47.9375
  BOX_HALF_IN_DOUBLE(dscalar_16,  0xd1fe);
  VLOAD_8(v0, 0xAA, 0xAA);
  //                6.19335365, -81.26284790, -77.74858093,  15.38204670,  27.37081337,  48.81098938, -82.18785095,  3.87765026, -34.03960037, -92.34690857,  46.98464203,  28.09385681,  58.44809723,  57.04935455, -44.62148285,  83.52678680
  VLOAD_32(v4,      0x40c62ff4,  0xc2a28694,  0xc29b7f46,  0x41761cdd,  0x41daf76d,  0x42433e74,  0xc2a4602e,  0x40782b6c,  0xc208288d,  0xc2b8b19e,  0x423bf046,  0x41e0c038,  0x4269cada,  0x4264328a,  0xc2327c66,  0x42a70db7);
  asm volatile("vfwnmacc.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_16));
  //                6.19335365, -285.94589233, -77.74858093, -1801.05395508,  27.37081337,  668.00445557, -82.18785095,  4607.11083984, -34.03960037, -3619.81323242,  46.98464203, -3323.79687500,  58.44809723, -3439.63916016, -44.62148285, -4421.87060547
  VCMP_U32(7, v4,  0x40c62ff4,  0xc38ef913,  0xc29b7f46,  0xc4e121ba,  0x41daf76d,  0x44270049,  0xc2a4602e,  0x458ff8e3,  0xc208288d,  0xc5623d03,  0x423bf046,  0xc54fbcc0,  0x4269cada,  0xc556fa3a,  0xc2327c66,  0xc58a2ef7);

  VSET(16, e32, m1);
  double dscalar_32;
  //                415907.75000000,  16644.92773438, -320087.15625000, -560497.81250000,  51200.66406250,  175961.67187500, -62272.61328125, -40134.65234375,  67972.27343750,  832511.06250000, -279323.15625000, -48243.37500000,  685093.43750000,  272952.25000000,  518086.00000000, -349626.18750000
  VLOAD_32(v2,      0x48cb1478,  0x468209db,  0xc89c4ae5,  0xc908d71d,  0x474800aa,  0x482bd66b,  0xc773409d,  0xc71cc6a7,  0x4784c223,  0x494b3ff1,  0xc8886365,  0xc73c7360,  0x49274257,  0x48854708,  0x48fcf8c0,  0xc8aab746);
  //                              -648299.93750000
  BOX_FLOAT_IN_DOUBLE(dscalar_32,  0xc91e46bf);
  VLOAD_8(v0, 0xAA, 0xAA);
  //               -3761.4446916116867214,  251037.4171459318604320, -832277.7590174797223881, -817938.7112226528115571, -640813.8540152770001441, -87111.6097838475834578, -748981.3983645441476256,  259451.7965630525723100, -469164.5467169298790395, -204901.8221613015048206,  97767.4262132318690419, -208046.9794710964197293, -303699.6372622016351670, -710697.5104083393234760, -907884.7086961114546284, -326406.2730544115183875
  VLOAD_64(v4,      0xc0ad62e3ae9e7200,  0x410ea4eb56509b38,  0xc129662b849df069,  0xc128f6256c256024,  0xc1238e5bb5417d8a,  0xc0f54479c1acb530,  0xc126db6acbf67002,  0x410fabde5f5c7320,  0xc11ca2b22fd69018,  0xc109032e93c94df0,  0x40f7de76d1c4f740,  0xc1096577d5f4f134,  0xc112894e8c8e766c,  0xc125b05305543dea,  0xc12bb4d96ada377b,  0xc113ec19179b935e);
  asm volatile("vfwnmacc.vf v4, %[A], v2, v0.t" :: [A] "f" (dscalar_32));
  //               -3761.4446916116867214,  10790654572.4701824188232422, -832277.7590174797223881, -363369878873.9254760742187500, -640813.8540152770001441,  114076027990.5677947998046875, -748981.3983645441476256, -26019552057.8339157104492188, -469164.5467169298790395,  539717074688.6307373046875000,  97767.4262132318690419, -31275968950.3095932006835938, -303699.6372622016351670,  176955637312.9947814941406250, -907884.7086961114546284, -226662309098.3402404785156250
  VCMP_U64(8, v4,  0xc0ad62e3ae9e7200,  0x420419629363c2ef,  0xc129662b849df069,  0xc25526a215567b3b,  0xc1238e5bb5417d8a,  0x423a8f760c56915b,  0xc126db6acbf67002,  0xc2183b8b6ce755ee,  0xc11ca2b22fd69018,  0x425f6a693fc0285e,  0x40f7de76d1c4f740,  0xc21d20c5a6d93d06,  0xc112894e8c8e766c,  0x424499b05f207f55,  0xc12bb4d96ada377b,  0xc24a63102e752b8d);
};

int main(void) {
  enable_vec();
  enable_fp();

  TEST_CASE1();
  TEST_CASE2();
  TEST_CASE3();
  TEST_CASE4();

  EXIT_CHECK();
}

